import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer
import bsddb
import struct
import json
import sys
import random
import os
import time

class Service:
    def __init__(self,dataset):
        maintime = time.time()
        self.dataset = dataset
        self.urlid = bsddb.btopen(dataset+'/urlid.bdb','r')
        self.idurl = bsddb.btopen(dataset+'/idurl.bdb','r')
        self.webgraph = open(dataset+'/webgraph.bin','rb').read()
        self.transposegraph = open(dataset+'/transposegraph.bin','rb').read()
        self.hostgraph = open(dataset+'/hostgraph.bin','rb').read()
        self.statdbpath = dataset+'/stat.json'
        self.webgraphindex = {}
        self.transposegraphindex = {}
        self.hostgraphindex = {}
        #read webgraph
        pos = 0
        while 1:
            try:
                src = struct.unpack_from('i',self.webgraph,pos)[0]
                self.webgraphindex[src] = pos
                pos += 4
                outdegree = struct.unpack_from('i',self.webgraph,pos)[0]
                pos += 4*(outdegree+1)
            except:
                break
        #read transposegraph 
        pos = 0
        while 1:
            try:
                src = struct.unpack_from('i',self.transposegraph,pos)[0]
                self.transposegraphindex[src] = pos
                pos += 4
                indegree = struct.unpack_from('i',self.transposegraph,pos)[0]
                pos += 4*(indegree+1)
            except:
                break
        #read hostgraph
        pos = 0 
        while 1:
            try:
                src = int(struct.unpack_from('i',self.hostgraph,pos)[0])
                self.hostgraphindex[src] = pos
                pos += 4
                total = struct.unpack_from('i',self.hostgraph,pos)[0]
                pos += 4*(total+1)
            except:
                break
        os.system('ps aux | grep server.py > memusage.txt')
        print 'Service Available'
        print time.time()-maintime

    def forward(self,urlrequest):
        ans = {}
        if self.urlid.has_key(urlrequest):
            srcid = int(self.urlid[urlrequest])
            
            startpos = self.webgraphindex[srcid]
            outdegree = struct.unpack_from('i',self.webgraph,startpos+4)[0]
            urllist = []
            pos = startpos
            for i in range(outdegree):
                destid = struct.unpack_from('i',self.webgraph,pos)[0]
                urllist.append(self.idurl[str(destid)])
                pos += 4
            ans['urlrequest'] = urlrequest
            ans['urlid'] = srcid
            ans['count'] = outdegree
            ans['result'] = urllist
        else:
            ans['error'] = True
            ans['message'] = 'Either URL not found or not match'

        return json.dumps(ans)

    def backward(self,urlrequest):
        ans = {}
        if self.urlid.has_key(urlrequest):
            destid = int(self.urlid[urlrequest])
            startpos = self.transposegraphindex[destid]
            indegree = int(struct.unpack_from('i',self.transposegraph,startpos+4)[0])
            urllist = []
            pos = startpos
            for i in range(int(indegree)):
                srcid = struct.unpack_from('i',self.transposegraph,pos)[0]
                urllist.append(self.idurl[str(srcid)])
                pos += 4
            ans['urlid'] = destid
            ans['count'] = indegree
            ans['result'] = urllist
            ans['urlrequest'] = urlrequest
        else:
            ans['error'] = True
            ans['message'] = 'Either URL not found or not match'

        return json.dumps(ans)

    def site(self,urlrequest):
        ans = {}
        if self.urlid.has_key(urlrequest):
            urllist = []
            hostid = int(self.urlid[urlrequest]) 
            if self.hostgraphindex.has_key(hostid):
                startpos = self.hostgraphindex[hostid]
                total = int(struct.unpack_from('i',self.hostgraph,startpos+4)[0])
                pos = startpos
                if total != 0:
                    for i in range(total):
                        srcid = struct.unpack_from('i',self.hostgraph,pos)[0]
                        urllist.append(self.idurl[str(srcid)])
                        pos += 4
                ans['urlid'] = hostid
                ans['count'] = total
                ans['result'] = urllist
                ans['urlrequest'] = urlrequest
            else:
                ans['error'] = True
                ans['message'] = 'Either URL not found or not match'
        else:
            ans['error'] = True
            ans['message'] = 'Either URL not found or not match'

        return json.dumps(ans)

    def list(self,value,maximum):
        ans = {}
        maximum = int(maximum)
        if value == 'source' :
            popularity = self.webgraphindex.keys()
            if maximum < len(popularity):
                sample = [self.idurl[str(id)] for id in random.sample(popularity,maximum)]
                ans['result'] = sample
            else:
                ans['error'] = True
                ans['message'] = 'The maximum value is bigger than popularity'
        elif value == 'destination' :
            popularity = self.transposegraphindex.keys()
            if maximum < len(popularity):
                sample = [self.idurl[str(id)] for id in random.sample(popularity,maximum)]
                ans['result'] = sample
            else:
                ans['error'] = True
                ans['message'] = 'The maximum value is bigger than popularity'
        return json.dumps(ans)

    def urltoid(self,url):
        ans = {}
        if self.urlid.has_key(url) :
            ans['url'] = url
            ans['id'] = self.urlid[url]
        else:
            ans['error'] = True
            ans['message'] = 'Either URL not found or not match'
        return json.dumps(ans)

    def idtourl(self,id):
        ans = {}
        if self.idurl.has_key(str(id)) :
            ans['url'] = self.idurl[str(id)]
            ans['id'] = str(id)
        else:
            ans['error'] = True
            ans['message'] = 'ID not found'
        return json.dumps(ans)

    def stat(self):
        statdb = json.loads(open(self.dataset+'/stat.json','r').read())
        return json.dumps(statdb)

    def close(self):
        self.idurl.close()
        self.urlid.close()

def main(dataset):
    try:
        PORT = 9999
        server = SimpleXMLRPCServer(('localhost',PORT))
        print 'Listening on port %d...' % (PORT)
        server.register_instance(Service(dataset))
        server.serve_forever()
    except KeyboardInterrupt:
        print 'Closed Connection'

if __name__ == '__main__' :
    dataset = 'wbCt100Sep08'
    main(dataset)
